package com.ltu.timkor6.gamesite.games.memory.client;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.ltu.timkor6.gamesite.shared.CompositeAbstract;
import com.ltu.timkor6.gamesite.shared.Result;

/**
 * Memory
 * 
 * @author tim
 */


public class MemoryComposite extends CompositeAbstract
{
	private static final String CSS_MEMORY_TABLE = "memory-table";
	private static final String CSS_MEMORY_PANEL = "memory-panel";
	private static final String CSS_MEMORY_CELL = "memory-cell";
	private static final String CSS_MEMORY_PANEL_ACTIVE = "memory-active";
	private static final String CSS_MEMORY_PANEL_FIXED = "memory-fixed";
		
	private Memory memory;
	private SimplePanel info;
	private ListBox number;
	private SimplePanel content;
	private FlexTable game;
	
	private int memorySize;
	private int matches;
	private int imagesLeft;
	
	private VerticalPanel infoPanel = new VerticalPanel();
	private Label labelImagesLeft = new Label();
	private Label labelMatches;
	
	private FocusPanel prevPanel;
	private FocusPanel restPanel;
	private int prevValue;
	private int totalMatches;
	private int tries;
	
	public MemoryComposite(Memory memory)
	{
		this.memory = memory;
		
		// Title
		final Label title = new Label("Memory");
		title.setStyleName("panelHeader");
		panel.add(title);
		
		info = new SimplePanel();
		info.setStyleName("game-info");
		content = new SimplePanel();
		content.setStyleName("game-playarea");
		
		panel.add(info);
		panel.add(content);
		
		loadModule();
		
		initWidget(panel);
	}
	
	public void loadModule()
	{
		this.info.setStyleName("errors");
		VerticalPanel startPanel = new VerticalPanel();
		
		Label label = new Label("Number of elements");
		
		number = new ListBox();
		number.addItem("2");
		number.addItem("4");
		number.addItem("8");
		number.addKeyPressHandler(new KeyPressHandler()
		{
			public void onKeyPress(KeyPressEvent event)
			{
				if(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER)
				{
					memory.checkSubmit();
				}
			}
		});
		
		Button submit = new Button("Start!");
		submit.addClickHandler(new ClickHandler()
		{
			public void onClick(ClickEvent event) {
				memory.checkSubmit();
			}
		});
		
		startPanel.add(label);
		startPanel.add(number);
		startPanel.add(submit);
		
		content.setWidget(startPanel);
	}
	
	public String getNumber()
	{
		return this.number.getItemText(this.number.getSelectedIndex());
	}
	
	public void addError(String error)
	{
		this.info.setWidget(new Label(error));
	}
	
	public void startGame()
	{
		this.prevPanel = null;
		this.restPanel = null;
		this.prevValue = -1;
		
		this.matches = 0;
		this.tries = 0;
		
		this.info.setWidget(infoPanel);
		this.info.setStyleName("game-info");
		
		infoPanel.add(labelImagesLeft);
		
		labelMatches = new Label("Matches: 0");
		infoPanel.add(labelMatches);
		
		// Set the outer bounds
		game = new FlexTable();
		game.setBorderWidth(1);
		game.setCellPadding(0);
		game.setCellSpacing(0);
		game.setStyleName(CSS_MEMORY_TABLE);
				
		// Draw our playing field
		FocusPanel focusPanel;
		for(int row = 0; row < this.memorySize; row++)
		{
			for(int column = 0; column < this.memorySize; column++)
			{
				focusPanel = new FocusPanel();
				focusPanel.setStyleName(CSS_MEMORY_PANEL);
				
				// Make all panels accept clicks
				focusPanel.addClickHandler(this.addClickPanel(row, column));
				
				game.setWidget(row, column, focusPanel);
				
				game.getCellFormatter().addStyleName(row, column, CSS_MEMORY_CELL);
			}
		}
		
		content.setWidget(game);
	}
	
	public void finished(Result result)
	{
		if(result == null)
		{
			Window.alert("You failed");
		}
		else
		{
			Window.alert("Finished with " + result.getPoints() + " points.");
		}
	}
	
	private ClickHandler addClickPanel(final int row, final int column)
	{
		ClickHandler handler =  new ClickHandler()
		{
			public void onClick(ClickEvent event)
			{
				checkColumn((FocusPanel) event.getSource(), row, column);
			}
		};
		return handler;
	}
	
	private void checkColumn(FocusPanel source, int row, int column)
	{
		if(source.getWidget() == null)
		{
			this.memory.image(row, column);
		}
	}
	
	public void setValue(int row, int column, int value)
	{
		FocusPanel focusPanel = (FocusPanel) this.game.getWidget(row, column);
		if(focusPanel.getWidget() == null)
		{
			focusPanel.add(new Label(String.valueOf(value)));
			
			// Match, keep both visible
			if(value == prevValue)
			{
				this.tries++;
				this.matches++;
				updateMatches();
				
				focusPanel.addStyleName(CSS_MEMORY_PANEL_FIXED);
				
				this.prevPanel.removeStyleName(CSS_MEMORY_PANEL_ACTIVE);
				this.prevPanel.addStyleName(CSS_MEMORY_PANEL_FIXED);
				
				// Reset value
				this.prevValue = -1;
				this.prevPanel = null;
				this.restPanel = null;
			}
			// First image, keep current visible
			else if(prevValue == -1)
			{
				if(restPanel != null)
				{
					this.restPanel.removeStyleName(CSS_MEMORY_PANEL_ACTIVE);
					restPanel.clear();
				}
				if(prevPanel != null)
				{
					this.prevPanel.removeStyleName(CSS_MEMORY_PANEL_ACTIVE);
					prevPanel.clear();
				}
				
				focusPanel.addStyleName(CSS_MEMORY_PANEL_ACTIVE);
				
				this.prevValue = value;
				this.prevPanel = focusPanel;
			}
			// No match, keep both visible
			else
			{
				focusPanel.addStyleName(CSS_MEMORY_PANEL_ACTIVE);
				this.prevPanel.addStyleName(CSS_MEMORY_PANEL_ACTIVE);
				
				this.tries++;
				this.prevValue = -1;
				this.restPanel = focusPanel;
			}
		}
	}

	public void updateMatches()
	{
		this.labelMatches.setText("Matches: " + this.matches);
		
		if(this.matches == this.totalMatches)
		{
			this.memory.finished();
		}
	}

	public void updateImagesLeft()
	{
		this.labelImagesLeft.setText("Images left: " + this.imagesLeft);
	}

	public void setMemorySize(int size)
	{
		this.memorySize = size;
		this.totalMatches = (size * size) / 2;
	}
}
